package licode.unisop.client.service.manager;

import licode.unisop.client.api.SopPlatform;
import licode.unisop.client.api.SopPlatformAuth;
import licode.unisop.client.api.SopPlatformMng;
import licode.unisop.client.config.SopConfig;
import licode.unisop.client.config.YmlPlatform;
import licode.unisop.client.info.SopPlatAuthInfo;
import licode.unisop.client.info.SopPlatHeartInfo;
import licode.unisop.client.utils.SopErrorCode;
import licode.unisop.client.utils.SopException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.lang.NonNull;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 管理平台和认证中心的交互，包括验证平台是否合法，
 * 只有平台验证后，后续登录认证操作才能继续完成
 *
 * @author WR
 */
@Slf4j
@Service
@EnableScheduling
class SopPlatformMngImpl implements SopPlatformMng, ApplicationRunner, BeanFactoryAware {
    @Resource
    private SopConfig sopConfig;

    @Resource
    private SopPlatformAuth platformAuth;

    @Resource
    private SopPlatformLocal sopPlatformLocal;

    private BeanFactory beanFactory;

    // 每10秒扫描一次
    @Scheduled(cron = "${uni-client.platform-heart:*/10 * * * * ?}")
    public synchronized void checkRenewPlatform() {
        List<YmlPlatform.Register> needAuthPl = new ArrayList<>();
        Map<String, YmlPlatform.Register> plClone = new HashMap<>(sopPlatformLocal.getPlInfos());

        for (Map.Entry<String, YmlPlatform.Register> entry: plClone.entrySet()) {
            YmlPlatform.Register platProp = entry.getValue();
            SopPlatform plAuth = sopPlatformLocal.getPlatforms().get(platProp.getId());

            try {
                if (null != plAuth) {
                    doRenewPlatform(plAuth, platProp);
                } else {
                    configPlatform(platProp);
                }
            } catch (SopException e) {
                log.warn("发送平台心跳检测异常[{}:{}]...", e.getCode(), e.getMessage());
                if (e.getCode() == SopErrorCode.PLATFORM_NOT_AUTH) {
                    if (null != plAuth && sopPlatformLocal.def() == plAuth) {
                        sopPlatformLocal.setDefPlatform(null);
                    }

                    if (sopPlatformLocal.getPlInfos().containsKey(entry.getKey())) {
                        needAuthPl.add(sopPlatformLocal.getPlInfos().get(entry.getKey()));
                    }

                    if (null != plAuth) {
                        sopPlatformLocal.getPTokens().remove(plAuth.getToken());
                    }

                    sopPlatformLocal.getPlatforms().remove(entry.getKey());
                }
            }
        }

        if (!needAuthPl.isEmpty()) {
            for (YmlPlatform.Register item: needAuthPl) {
                configPlatform(item);
            }
        }
    }

    private void doRenewPlatform(SopPlatform plAuth, YmlPlatform.Register platProp) {
        SopPlatHeartInfo req = new SopPlatHeartInfo();
        req.setRealmId(plAuth.getRealmId());
        req.setTenantId("default");
        req.setPlatformToken(plAuth.getToken());
        req.setInnerToken(plAuth.getAuthPlatform().getInnerToken());
        req.setPlatformId(plAuth.getAuthPlatform().getPlatformId());
        req.setPlatformSecret(platProp.getSecret());
        platformAuth.renew(req);
    }

    private void configPlatform(YmlPlatform.Register ptItem) {
        String plId = ptItem.getId();
        SopPlatform plat = beanFactory.getBean(SopPlatform.class);

        sopPlatformLocal.getPlInfos().putIfAbsent(plId, ptItem);

        try {
            // 验证默认的平台
            plat.auth(SopPlatAuthInfo.builder()
                            .id(ptItem.getId())
                            .secret(ptItem.getSecret())
                            .realmId(ptItem.getRealmId())
                    .build());

            sopPlatformLocal.getPlatforms().put(plId, plat);
            if (null == sopPlatformLocal.def()) {
                sopPlatformLocal.setDefPlatform(plat);
            }

            sopPlatformLocal.getPTokens().put(plat.getToken(), plat);
            log.info("初始化平台成功,{}->[{}:{}]", plat.getName(), plat.getId(), plat.getToken());
        }  catch (SopException e) {
            log.info("初始化平台失败,{}->[{}:{}]",
                    ptItem.getId(), e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.info("初始化平台失败,{}", e.getMessage());
        }
    }

    @Override
    public synchronized void run(ApplicationArguments args) {
        log.info("开始初始化平台：{}",  sopConfig);
        if (sopConfig.getPlatform().isValid()) {
            for (YmlPlatform.Register platform : sopConfig.getPlatform().getRegisters()) {
                configPlatform(platform);
            }
        }
    }

    @Override
    public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public List<String> getPlatformIdList() {
        return sopPlatformLocal.getPlatformIdList();
    }

    @Override
    public SopPlatform getPlatform(String name) {
        return sopPlatformLocal.getPlatform(name);
    }

    @Override
    public SopPlatform getPlatformByToken(String token) {
        return sopPlatformLocal.getPlatformByToken(token);
    }

    @Override
    public SopPlatform def() {
        return sopPlatformLocal.def();
    }

    @Override
    public boolean register(String platformId, String secret) {
        YmlPlatform.Register prop = new YmlPlatform.Register();
        prop.setId(platformId);
        prop.setSecret(secret);
        configPlatform(prop);
        return true;
    }

}
